package com.bugly

import android.content.Context
import android.os.Process
import android.os.SystemClock
import android.text.TextUtils
import com.blankj.utilcode.util.AppUtils
import com.blankj.utilcode.util.DeviceUtils
import com.blankj.utilcode.util.ThreadUtils
import com.bugly.log.MyLogger
import com.tencent.bugly.Bugly
import com.tencent.bugly.beta.Beta
import com.tencent.bugly.beta.download.DownloadListener
import com.tencent.bugly.beta.download.DownloadTask
import com.tencent.bugly.beta.upgrade.UpgradeListener
import com.tencent.bugly.beta.upgrade.UpgradeStateListener
import com.tencent.bugly.crashreport.CrashReport
import com.wanxing.sellerapp.BuildConfig
import com.wanxing.sellerapp.config.AppConfig
import java.io.BufferedReader
import java.io.FileReader
import java.io.IOException
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicLong

object BuglyHelper {

    private const val BUGLY_APPID = "0e09caeb24"

    private val canCheck = AtomicBoolean(false)
    private val nextCheckTime = AtomicLong(0)

    fun init(applicationContext: Context) {

        configUpdate()
        val strategy = configLogger(applicationContext)
//        Bugly.init(applicationContext, BUGLY_APPID, /*isDebug*/AppUtils.isAppDebug(), strategy)
        Bugly.init(applicationContext, BUGLY_APPID, false, strategy)
        if (AppUtils.isAppDebug()){
            Bugly.setIsDevelopmentDevice(applicationContext, BuildConfig.DEBUG);
        }
        Bugly.setUserId(applicationContext, DeviceUtils.getAndroidID())
    }

    private fun configLogger(applicationContext: Context) : CrashReport.UserStrategy {
        val strategy = CrashReport.UserStrategy(applicationContext)
        strategy.appChannel = AppConfig.channel//设置渠道
        strategy.appVersion = AppUtils.getAppVersionName()    //App的版本
        strategy.appPackageName = AppUtils.getAppPackageName()  //App的包名
        val packageName: String = applicationContext.packageName
        val processName = getProcessName(Process.myPid())
        strategy.isUploadProcess = processName == null || processName == packageName;
        return strategy
    }

    //设置下次检测时间，避免正在安装升级时，检查到升级后重新下载覆盖原来的包，导致安装时，包解析失败
    private fun setNextCheckTime() {
        nextCheckTime.set(SystemClock.elapsedRealtime() + 12 * 1000L)
    }

    private fun configUpdate() {
        Beta.autoInit = true
        Beta.autoCheckUpgrade = true
        Beta.autoCheckAppUpgrade = true
        Beta.autoDownloadOnWifi = true
        Beta.autoInstallApk = true
        Beta.upgradeListener = UpgradeListener { ret, strategy, isManual, isSilence ->
            MyLogger.debug( "Upgrade.UpgradeListener", "ret = $ret, isManual = $isManual, isSilence = $isSilence")
            if (strategy != null) {
                if (strategy.versionCode > AppUtils.getAppVersionCode()) {
                    MyLogger.debug("upgrade", "versionCode = ${strategy.versionCode}")
                    Beta.startDownload()
                    Beta.registerDownloadListener(object : DownloadListener {
                        override fun onReceive(task: DownloadTask?) {
                            MyLogger.debug("Upgrade.DownloadListener", "onReceive")
                            setNextCheckTime()
                        }

                        override fun onCompleted(task: DownloadTask?) {
                            MyLogger.debug("Upgrade.DownloadListener", "onCompleted")
                            setNextCheckTime()
                        }

                        override fun onFailed(task: DownloadTask?, p1: Int, p2: String?) {
                            MyLogger.debug("Upgrade.DownloadListener", "onFailed")
                        }

                    })
                }
            }
            return@UpgradeListener
        }
        Beta.upgradeStateListener = object : UpgradeStateListener {
            override fun onUpgradeSuccess(isManual: Boolean) {
                MyLogger.debug("Upgrade.UpgradeStateListener", "onUpgradeSuccess")
                canCheck.set(true)
            }

            override fun onUpgradeFailed(isManual: Boolean) {
                MyLogger.debug("Upgrade.UpgradeStateListener", "onUpgradeFailed")
                canCheck.set(true)
            }

            override fun onUpgrading(isManual: Boolean) {
                MyLogger.debug("Upgrade.UpgradeStateListener", "onUpgrading")
            }

            override fun onDownloadCompleted(p0: Boolean) {
                MyLogger.debug("Upgrade.UpgradeStateListener", "onDownloadCompleted")
                Beta.unregisterDownloadListener()
            }

            override fun onUpgradeNoVersion(isManual: Boolean) {
                MyLogger.info("Upgrade.UpgradeStateListener", "onUpgradeNoVersion")
                canCheck.set(true)
            }
        }

    }

    private fun getProcessName(pid: Int): String? {
        var reader: BufferedReader? = null
        try {
            reader = BufferedReader(FileReader("/proc/$pid/cmdline"))
            var processName: String = reader.readLine()
            if (!TextUtils.isEmpty(processName)) {
                processName = processName.trim { it <= ' ' }
            }
            return processName
        } catch (throwable: Throwable) {
            throwable.printStackTrace()
        } finally {
            try {
                reader?.close()
            } catch (exception: IOException) {
                exception.printStackTrace()
            }
        }
        return null
    }

    fun upgradeChecker() {
        ThreadUtils.executeByCachedAtFixRate( object : ThreadUtils.Task<Boolean>() {
            override fun doInBackground(): Boolean {
                return true
            }

            override fun onSuccess(result: Boolean?) {
                if (canCheck.get() && (nextCheckTime.get() == 0L || nextCheckTime.get() < SystemClock.elapsedRealtime())) {
                    Beta.checkAppUpgrade(false, true)
                }
            }

            override fun onCancel() {

            }

            override fun onFail(t: Throwable?) {
            }

        }, 5, 5, TimeUnit.SECONDS)


    }
}